package multithread.framework.xml;

import java.lang.reflect.Array;

import multithread.framework.constant.XMLConfigConstant;
import multithread.framework.utility.Utilities;

import org.jdom.Element;

public abstract class ParamElement extends Element implements IVerifiable {
	private static final long serialVersionUID = -1895832707212994624L;

	public static ParamElement createParamElement(Class<?> paramType,
			Object paramValue) {
		if (paramType == null)
			return null;
		if (paramType.isArray()) {
			return new ArrayParamElement(
					Utilities.ARRAYTOELEMENTTYPE.get(paramType), paramValue);
		} else {
			return new SimpleParamElement(paramType, paramValue);
		}
	}

	private Object paramValue;

	protected ParamElement(Object value) {
		super(XMLConfigConstant.PARAM_ELEMENT);
		this.paramValue = value;
	}

	protected Object getParamValue() {
		return paramValue;
	}

	/**
	 * 
	 * Simple ParamElement like
	 * 
	 * <pre>
	 * &lt;param class="int" value="4"/&gt;
	 * &lt;param class="java.lang.String" value="Hello"/&gt;
	 * </pre>
	 */
	private static class SimpleParamElement extends ParamElement {
		private static final long serialVersionUID = 3776851210636387324L;
		private Class<?> paramClass = null;

		public SimpleParamElement(Class<?> clz, Object value) {
			super(value);
			paramClass = clz;
			init();
		}

		private void init() {
			setAttribute(XMLConfigConstant.CLASS_PROPERTY, paramClass.getName());
			setAttribute(XMLConfigConstant.VALUE_PROPERTY, getParamValue()
					.toString());
		}

		@Override
		public boolean validate() {
			return true;
		}

	}

	/**
	 * Array type ParamElement like
	 * 
	 * <pre>
	 * &lt;param elementType="java.lang.String"&gt;
	 *  &lt;values&gt;
	 *   &lt;value&gt;str1&lt;/value&gt;
	 *   &lt;null/&gt;
	 *  &lt;/values&gt;
	 * &lt;/param&gt;
	 * </pre>
	 */
	private static class ArrayParamElement extends ParamElement {
		private static final long serialVersionUID = -8337115357640783035L;
		private Class<?> elementClassType = null;
		private Element values;

		public ArrayParamElement(Class<?> elementType, Object value) {
			super(value);
			elementClassType = elementType;
			init();
		}

		private void init() {
			setAttribute(XMLConfigConstant.ELEMENT_TYPE_PROPERTY,
					elementClassType.getName());
			addValuesElement();
		}

		private void addValuesElement() {
			synchronized (this) {
				if (values == null) {
					values = new Element(XMLConfigConstant.VALUES_ELEMENT);
					addContent(values);
				}
			}
			for (int i = 0; i < Array.getLength(getParamValue()); i++) {
				Object valueText = Array.get(getParamValue(), i);
				if (valueText != null) {// null Element
					Element valueElement = new Element(
							XMLConfigConstant.VALUE_ELEMENT);
					valueElement.setText(valueText.toString());
					values.addContent(valueElement);
				} else {// value Element
					Element nullValueElement = new Element(
							XMLConfigConstant.NULL_ELEMENT);
					values.addContent(nullValueElement);
				}
			}
		}

		@Override
		public boolean validate() {
			return getParamValue() == null ? false : Array
					.getLength(getParamValue()) > 0 ? true : false;
		}

	}

}
